package career_service

import (
	"encoding/json"
	"fmt"
	"io"
	"math"
	"math/rand"
	"net/http"
	"peilian-api/app/controllers/web_report"
	"peilian-api/app/global/common"
	"peilian-api/app/global/databases/tables"
	"peilian-api/app/global/errors"
	"peilian-api/app/global/log"
	"peilian-api/app/global/variable"
	"peilian-api/app/model"
	"peilian-api/app/services/report_service"
	"peilian-api/utils/sdk"
	"peilian-api/utils/tools"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

type SpecialService struct{}

func (s *SpecialService) GetSpecialCareerList(ctx *gin.Context, ccr model.CareerCriteriaRes) ([]model.CareerCriteriaInfo, error) {
	// 1.根据type获取
	var out []model.CareerCriteriaInfo
	level := ccr.Level
	careerId := ccr.CareerId
	var levelNum = 0
	// 2. 查询redis
	if level == "基础" {
		levelNum = 1
	} else {
		levelNum = 2
	}
	sc := variable.DB.Redis.Get(fmt.Sprintf(common.RedisSpecialCriteriaKey, careerId, levelNum))
	res, _ := sc.Result()
	if len(res) != 0 {
		var resultMap []model.CareerCriteriaInfo
		err := json.Unmarshal([]byte(res), &resultMap)
		for i := 0; i < len(resultMap); i++ {
			if !resultMap[i].IsEnable {
				continue
			}
			resultMap[i].Describe = fmt.Sprintf(resultMap[i].Describe, resultMap[i].Num)
			out = append(out, resultMap[i])
		}
		if err == nil {
			return out, nil
		}
	}
	return out, nil
}

func (s *SpecialService) GetSpecialTopics(ctx *gin.Context, st model.SpecialTopicsRes) (model.SpecialTopicsResp, *errors.ErrRes) {
	// 1. 先获取uid，并记录该用户是否抽过该道题
	var out model.SpecialTopicsResp
	uid, exists := ctx.Get("uid")
	if !exists {
		return out, errors.NewErrInfo(errors.SessionUidErrorCode, fmt.Errorf("用户未登录"))
	}
	// 根据uid获取user信息
	us, _ := tables.GetAgentInfoByUid(uid.(uint))

	if us.Type == tables.UserTypeAnonymous && us.IsMember != tables.MemberStatusHas {
		return out, errors.NewErrInfo(errors.SessionUidErrorCode, fmt.Errorf("您需要购买会员"))
	}
	careerId := st.CareerId
	criteria := st.Criteria
	level := st.Level
	// 2. 获取该用户面试过的所有题目
	redisKey := fmt.Sprintf(common.RedisSpecialTopicKey, uid, careerId, criteria, level)
	sc := variable.DB.Redis.Get(redisKey)
	sr, _ := sc.Result()
	var whereIds = sr
	if len(whereIds) != 0 { // 说明没有数据
		// 解析数据
		whereIds = strings.Trim(whereIds, "[")
		whereIds = strings.Trim(whereIds, "]")
	}
	var questions []tables.Question
	var whereStr = fmt.Sprintf("career_id = %d and level = '%s'", careerId, level)
	// 3. 查询题目
	if careerId == 2 { // 公务员
		whereStr = fmt.Sprintf("%s and criteria = '%s' and type != '%s'", whereStr, criteria, tables.QExtra)
		if len(whereIds) != 0 {
			questions, _ = new(tables.Question).GetQuestionsByWhereStr(whereStr + " and id not in (" + whereIds + ")")
		}
		if len(whereIds) == 0 || len(questions) == 0 {
			questions, _ = new(tables.Question).GetQuestionsByWhereStr(whereStr)
			variable.DB.Redis.Del(redisKey) // 忽略该错误
		}
	} else if careerId == 1 { // 非公务员 & 通用题库的
		// 查询special_question表
		var sq []tables.SpecialQuestion
		whereStr = fmt.Sprintf("career_id in (1,14,15) and level = '%s' and front_show_tag = '%s'", level, criteria) // 新第一个whereStr
		if len(whereIds) != 0 {
			where := fmt.Sprintf("%s and question_id not in (%s)", whereStr, whereIds)
			sq, _ = new(tables.SpecialQuestion).GetListByWhere(where, map[string]interface{}{})
		}
		if len(whereIds) == 0 || len(sq) == 0 {
			sq2, err := new(tables.SpecialQuestion).GetListByWhere(whereStr, map[string]interface{}{})
			if err != nil {
				return out, errors.NewErrInfo(errors.DatabaseMysqlErrorCode, fmt.Errorf("网络异常，请重新操作"))
			}
			variable.DB.Redis.Del(redisKey) // 忽略该错误
			sq = sq2
		}
		for _, v := range sq {
			v.Question.CriteriaTag = v.Criteria
			questions = append(questions, v.Question)
		}
	} else { // 其他成员
		var sq []tables.SpecialQuestion
		whereStr = fmt.Sprintf("%s and front_show_tag = '%s' ", whereStr, criteria) // 复用之前的whereStr
		if len(whereIds) != 0 {
			where := fmt.Sprintf("%s and question_id not in (%s)", whereStr, whereIds)
			sq, _ = new(tables.SpecialQuestion).GetListByWhere(where, map[string]interface{}{})
		}
		if len(whereIds) == 0 || len(sq) == 0 {
			sq2, err := new(tables.SpecialQuestion).GetListByWhere(whereStr, map[string]interface{}{})
			if err != nil {
				return out, errors.NewErrInfo(errors.DatabaseMysqlErrorCode, fmt.Errorf("网络异常，请重新操作"))
			}
			variable.DB.Redis.Del(redisKey) // 忽略该错误
			sq = sq2
		}
		for _, v := range sq {
			v.Question.CriteriaTag = v.Criteria
			questions = append(questions, v.Question)
		}
	}

	// 4. 随机抽题
	var randNum = 0
	if len(questions) > 1 {
		randNum = rand.Intn(len(questions) - 1)
	}

	q := questions[randNum]

	// 5. 获取职业名称
	career, _ := new(tables.Career).GetCareerInfoListByWhereStr(fmt.Sprintf("id = %d", careerId))

	// 将问题写入到数据库
	var srr tables.SpecialRecord
	srr.UserID = uid.(uint)
	srr.UserName = us.Name
	srr.Type = us.Type
	srr.School = us.School
	srr.Academy = us.Academy
	srr.Profession = us.Profession
	srr.Grade = us.Grade
	srr.Education = us.Education
	srr.UserPhone = us.Phone

	srr.CareerID = q.CareerID
	srr.CareerName = career[0].Name
	srr.QuestionID = q.ID
	srr.QuestionText = q.Text
	srr.AnsAnalysis = q.AnsAnalysis
	srr.Criteria = criteria
	srr.Level = level
	srr.Status = 0
	srr.MainPointScoreDetail = q.PointText
	srr.QuestionOrigin = q.QuestionOrigin
	srr.AnsAnalysisTag = q.AnsAnalysisTag
	srr.CriteriaTag = q.CriteriaTag
	srr.TotalScore = -1 // 默认是-1
	// srr.TrainAt = time.Now()

	result, err := new(tables.SpecialRecord).Create(srr)
	if err != nil {
		return out, errors.NewErrInfo(20013, fmt.Errorf("专项练习开启失败，请重试~"))
	}
	var questionOrigin []string
	err2 := json.Unmarshal([]byte(q.QuestionOrigin), &questionOrigin)
	if err2 != nil {
		questionOrigin = make([]string, 0)
	}
	out.Sid = int64(result.ID)
	out.Qid = int64(q.ID)
	out.Text = q.Text
	out.Video = q.SpecialVideo
	out.QuestionOrigin = questionOrigin
	return out, nil
}

// 获取用户训练的列表
func (s *SpecialService) GetSpecialList(ctx *gin.Context, pps model.PagePageSize) ([]model.SpecialInfo, int64, *errors.ErrRes) {
	// 1. 先获取uid，并记录该用户是否抽过该道题
	var out []model.SpecialInfo
	uid, exists := ctx.Get("uid")
	if !exists {
		return out, 0, errors.NewErrInfo(errors.SessionUidErrorCode, fmt.Errorf("用户未登录"))
	}

	page := pps.Page
	pageSize := pps.PageSize
	var whereMap map[string]interface{}
	whereMap = make(map[string]interface{}, 0)
	whereMap["user_id"] = uid
	whereMap["status"] = tables.SucStatus

	sr, count, err := new(tables.SpecialRecord).GetSpecialListByWhere(whereMap, "", "", "finish_at desc", int(page), int(pageSize))
	if err != nil {
		return out, 0, errors.NewErrInfo(20012, fmt.Errorf("请刷新重试"))
	}

	for i := 0; i < len(sr); i++ {
		var si model.SpecialInfo
		si.AnsAnalysis = sr[i].AnsAnalysis
		si.AnswerText = sr[i].AnswerText
		si.AnswerVideo = sr[i].AnswerAudio
		si.CareerName = sr[i].CareerName
		si.Criteria = sr[i].Criteria
		si.FinishTime = sr[i].FinishAt.Format("2006-01-02 15:04:05")
		si.TrainTime = sr[i].TrainAt.Format("2006-01-02 15:04:05")
		si.Sid = int64(sr[i].ID)
		si.SpeakTime = sr[i].SpeakTime
		si.Text = sr[i].QuestionText
		si.TotalScore = int64(sr[i].TotalScore)
		out = append(out, si)
	}

	return out, count, nil
}

// 获取用户的训练详情
func (s *SpecialService) GetSpecialDetail(ctx *gin.Context, id int64) (model.SpecialInfo, *errors.ErrRes) {
	var out model.SpecialInfo
	var whereMap map[string]interface{}
	whereMap = make(map[string]interface{}, 0)
	whereMap["id"] = id
	sr, _, err := new(tables.SpecialRecord).GetSpecialListByWhere(whereMap, "", "", "", -1, -1)
	if err != nil {
		return out, nil
	}
	var ansAnalysisTag []string
	err2 := json.Unmarshal([]byte(sr[0].AnsAnalysisTag), &ansAnalysisTag)
	if err2 != nil {
		ansAnalysisTag = make([]string, 0)
	}

	var totalScore int64 = -1
	// totalScore := int64(sr[0].TotalScore)
	if sr[0].TotalScore < 0 {
		// 判断当前超过一分钟吗
		t := time.Now().Unix() - sr[0].FinishAt.Unix()
		if t > 30 && t < 1000 { // 防止 finishAt 是 0000-00-00 00:00:00.000
			totalScore = 0
			// 无关系更新结果
			new(tables.SpecialRecord).UpdateSpecial(whereMap, "", map[string]interface{}{"total_score": totalScore}, 1)
		}
	} else if sr[0].TotalScore == 0 {
		t := time.Now().Unix() - sr[0].FinishAt.Unix()
		if t < 20 {
			totalScore = -1
		}
	} else {
		totalScore = int64(sr[0].TotalScore)
	}

	out.AnsAnalysis = sr[0].AnsAnalysis
	out.AnswerText = sr[0].AnswerText
	out.AnswerVideo = sr[0].AnswerAudio
	out.Audio = sr[0].Audio
	out.CareerName = sr[0].CareerName
	out.Criteria = sr[0].Criteria
	out.FinishTime = sr[0].FinishAt.Format("2006-01-02 15:04:05")
	out.TrainTime = sr[0].TrainAt.Format("2006-01-02 15:04:05")
	out.Sid = int64(sr[0].ID)
	out.SpeakTime = sr[0].SpeakTime
	out.Text = sr[0].QuestionText
	out.TransStatus = uint(sr[0].TransStatus)
	out.TotalScore = totalScore
	out.AnsAnalysisTag = ansAnalysisTag

	return out, nil
}

// 是否有帮助
func (s *SpecialService) UpdateSpecialIsHelp(ctx *gin.Context, ser model.SpecialEvaluateRes) *errors.ErrRes {
	sid := ser.Sid
	isHelp := ser.IsHelp
	var whereMap map[string]interface{}
	whereMap = make(map[string]interface{}, 0)
	whereMap["id"] = sid

	var updateMap map[string]interface{}
	updateMap = make(map[string]interface{}, 0)
	updateMap["is_help"] = isHelp
	_, err := new(tables.SpecialRecord).UpdateSpecial(whereMap, "", updateMap, 1)
	if err != nil {
		return errors.NewErrInfo(10001, fmt.Errorf("数据操作失败，请重试"))
	}
	return nil
}

// 专项练习更新redis状态
func (s *SpecialService) updateSpecialScoreRedis(status, score, specialId int) error {
	d := variable.DB.MySQL.Model(&tables.SpecialRecord{}).Where("id = ?", specialId).Updates(map[string]interface{}{"status": status, "total_score": score}).Limit(1)
	if d.Error != nil {
		return d.Error
	}
	// 将对应的分数更新进入redis
	sc := variable.DB.Redis.HSet(fmt.Sprintf(common.RedisSpecialInfoKey, specialId), common.RedisHmapScore, score)
	_, err := sc.Result()
	if err != nil {
		return err
	}
	// 将对应的状态更新进入redis
	sc = variable.DB.Redis.HSet(fmt.Sprintf(common.RedisSpecialInfoKey, specialId), common.RedisHmapTrans, status)
	_, err = sc.Result()
	if err != nil {
		return err
	}
	return nil

}

// 专项练习评分
func (s *SpecialService) UpdateScore(ctx *gin.Context, sid int) error {
	var whereMap map[string]interface{}
	whereMap = make(map[string]interface{}, 0)
	whereMap["id"] = sid
	specialList, _, err := new(tables.SpecialRecord).GetSpecialListByWhere(whereMap, "", "", "", -1, -1)
	if err != nil {
		return err
	}
	for i := 0; i < 30; i++ { // sleep 等待answerText 写入数据库
		if len(specialList) != 0 && len(specialList[0].AnswerText) == 0 {
			log.Logger.InfoF(ctx, fmt.Sprintf("等待时间:%d, answerText:%s", i*200, specialList[0].AnswerText))
			time.Sleep(200 * time.Millisecond)
			specialList, _, _ = new(tables.SpecialRecord).GetSpecialListByWhere(whereMap, "", "", "", -1, -1)
		} else {
			break
		}
	}
	// check数据完整性
	// if len(specialList) != 0 && len(specialList[0].AnswerText) == 0 { // 评分未成功 加入队列
	// 	return nil
	// }
	specialInfo := specialList[0]
	// 评分
	if specialInfo.CareerID == 2 {
		err = s.UpdateScoreGongwuayun(ctx, &specialInfo)
	} else {
		err = s.UpdateScoreSecondOther(ctx, &specialInfo)
	}
	if err != nil {
		// 加入redis，重试评分
		variable.DB.Redis.LPush(common.RedisSpecialQueue, specialInfo.ID)
		log.Logger.ErrorMsgF(ctx, fmt.Sprintf("专项练习评分失败,系统已经自动处理,id:[%d], info: %s", int(specialInfo.ID), err.Error()))
	}
	return nil
}

// 专项练习-评分--其他
func (s *SpecialService) UpdateScoreOther(ctx *gin.Context, special *tables.SpecialRecord) error {
	id := special.ID
	jobName := special.CareerName
	ansText := special.AnswerText
	speakTime := special.SpeakTime
	ansAnalysisTag := special.AnsAnalysisTag
	if len(ansText) < 50 || speakTime < 10 {
		// 将对应的分数更新进入redis
		return s.updateSpecialScoreRedis(tables.SucStatus, 0, int(id))
	}
	// 评分
	partCacheListStr := web_report.FetchLabelsCache(ctx, jobName, ansText)
	variable.DB.MySQL.Model(&tables.SpecialRecord{}).Where("id = ?", id).Updates(map[string]interface{}{"part_labels_cache": partCacheListStr}).Limit(1)

	var partLabelCache interface{}
	_ = json.Unmarshal([]byte(partCacheListStr), &partLabelCache)

	var specialInfoAnsAnalysis = make([]interface{}, 0)
	_ = json.Unmarshal([]byte(ansAnalysisTag), &specialInfoAnsAnalysis)
	respStr := report_service.FetchEvalByLabelsZhuanxiang(ctx, jobName, []interface{}{partLabelCache}, specialInfoAnsAnalysis, []interface{}{special.CriteriaTag})
	var ebzResp model.EvalByLabelsZhuanxiangResp
	_ = json.Unmarshal([]byte(respStr), &ebzResp)
	score, _ := strconv.Atoi(fmt.Sprintf("%1.0f", ebzResp.RawScore*100))
	return s.updateSpecialScoreRedis(tables.SucStatus, score, int(id))
}

func (s *SpecialService) UpdateScoreSecondOther(ctx *gin.Context, special *tables.SpecialRecord) error {
	log.Logger.InfoF(ctx, fmt.Sprintf("special:[%+v]", special))
	ans_text := special.AnswerText
	speakTime := special.SpeakTime
	var themeScore float64 = 0.00 // 主题评分
	var updates map[string]interface{}
	updates = make(map[string]interface{}) // 更新数据
	if len(ans_text) < 50 || speakTime < 10 {
		return s.updateSpecialScoreRedis(tables.SucStatus, 0, int(special.ID))
	} else {
		// 重试3次
		for i := 0; i < 3; i++ {
			if len(special.AnswerAudio) == 0 { // 查询上传音频
				specialList, _, _ := new(tables.SpecialRecord).GetSpecialListByWhere(map[string]interface{}{"id": special.ID}, "", "", "", -1, -1)
				if len(specialList) == 0 {
					return fmt.Errorf("get special is error")
				}
				special = &specialList[0]
				time.Sleep(150 * time.Millisecond)
				continue
			}
			break
		}
		if len(special.AnswerAudio) == 0 {
			return fmt.Errorf("get special audio is error")
		}
		// asr 评分
		asrScore := report_service.FetchLanguageComment(special.AnswerText) // asr_score
		// 语调气场
		toneScore := report_service.FetchEmotion(variable.Config.UfsInfo.UfsUrl + variable.Config.UfsInfo.BucketPrefix + special.AnswerAudio)
		// 自信度(语气词评分)
		moodScore := report_service.FetchMood(special.AnswerText)
		// 语言流畅度
		languageFluencyScore := asrScore*0.5 + moodScore*0.5
		// 语言表达能力 = (语言流畅度+语调) / 2
		languageScore := (toneScore + languageFluencyScore) / 2.0

		// 主题评分
		themeScore = report_service.FetchFocusTopicScore(special.QuestionText, ans_text)

		// 逻辑性评分
		logicScore := report_service.FetchLogicScore(special.QuestionText, ans_text)

		// 题目解析里涉及到的标签词，会影响neg_word_score_dict的结果
		analyzeLabels := make([]string, 0)
		analyzeLabelsList := make([]string, 0)
		_ = json.Unmarshal([]byte(special.Question.KeyWords), &analyzeLabels)
		analyzeLabelsList = append(analyzeLabelsList, analyzeLabels...)

		var partLabelCache interface{}
		// 将缓存起来的标签词评测中间结果合并起来，用于最终的标签词获取
		labelCacheList := make([]interface{}, 0)
		partLabelsCache := report_service.FetchLabelsCache(ctx, special.CareerName, ans_text)
		_ = json.Unmarshal([]byte(partLabelsCache), &partLabelCache)
		if partLabelCache != nil {
			labelCacheList = append(labelCacheList, partLabelCache)
		}
		// 做一个map集合
		labelCacheMap := make(map[string]interface{}, 0)
		_ = json.Unmarshal([]byte(partLabelsCache), &labelCacheMap)
		var lableWordList []string // 算法识别标签
		lableWordListValue, _ := json.Marshal(labelCacheMap["label_word_list"])
		_ = json.Unmarshal(lableWordListValue, &lableWordList)
		// 能力识别算法接口
		reqStruct := map[string]interface{}{
			"job_name":           special.CareerName,
			"label_extract_list": labelCacheList,
			"analyze_labels":     analyzeLabelsList,
		}
		reqData, _ := json.Marshal(reqStruct)
		evaluateResp := report_service.FetchEvaluationScore(reqData)
		evaluateScore := evaluateResp.EvalScore * 100
		jsonData, _ := json.Marshal(evaluateResp)

		// 初始评分
		topicScore := evaluateScore*0.4 + themeScore*0.3 + languageScore*0.15 + logicScore*0.15
		if len(lableWordList) != 0 && tools.Contains(lableWordList, special.CriteriaTag) {
			topicScore = math.Sqrt(topicScore)
		}

		updates["asr_score"] = asrScore
		updates["tone"] = toneScore
		updates["mood"] = moodScore
		updates["language_fluency_score"] = languageFluencyScore
		updates["language_score"] = languageScore
		updates["theme_score"] = themeScore
		updates["topic_score"] = topicScore
		updates["part_labels_cache"] = partLabelsCache
		updates["evaluation"] = string(jsonData)
		updates["logic_score"] = logicScore

		// 将对应的分数更新进入redis
		if int(topicScore) == 0 && (themeScore > 10 || moodScore > 10 || special.MainPointScore > 10) {
			fmt.Println("说明评分不准确，不予评分")
		} else {
			log.Logger.InfoF(ctx, fmt.Sprintf("total_score得分%d", int(topicScore)))
			sc := variable.DB.Redis.HSet(fmt.Sprintf(common.RedisSpecialInfoKey, special.ID), common.RedisHmapScore, int(topicScore))
			_, err := sc.Result()
			if err != nil {
				return err
			}
		}
		// 更新对应的评分项
		d := variable.DB.MySQL.Model(&tables.SpecialRecord{}).Where("id = ?", special.ID).Updates(updates).Limit(1)
		if d.Error != nil {
			return d.Error
		}
		// 更新redis & 结果得分 & 状态
		return s.updateSpecialScoreRedis(tables.SucStatus, int(topicScore), int(special.ID))
	}
}

// 专项练习-评分--公务员
func (s *SpecialService) UpdateScoreGongwuayun(ctx *gin.Context, special *tables.SpecialRecord) error {
	log.Logger.InfoF(ctx, fmt.Sprintf("special:[%+v]", special))
	ans_text := special.AnswerText
	speakTime := special.SpeakTime
	var pointScore float64 = special.MainPointScore // 要点关键词评分
	var themeScore float64 = 0.00                   // 主题评分
	var updates map[string]interface{}
	updates = make(map[string]interface{}) // 更新数据
	var topicScore float64 = 0.00
	if len(ans_text) < 50 || speakTime < 10 {
		return s.updateSpecialScoreRedis(tables.SucStatus, 0, int(special.ID))
	} else {
		// 重试3次
		for i := 0; i < 3; i++ {
			if len(special.AnswerAudio) == 0 { // 查询上传音频
				specialList, _, _ := new(tables.SpecialRecord).GetSpecialListByWhere(map[string]interface{}{"id": special.ID}, "", "", "", -1, -1)
				if len(specialList) == 0 {
					return fmt.Errorf("get special is error")
				}
				special = &specialList[0]
				time.Sleep(150 * time.Millisecond)
				continue
			}
			break
		}
		if len(special.AnswerAudio) == 0 {
			return fmt.Errorf("get special audio is error")
		}
		// asr 评分
		asrScore := report_service.FetchLanguageComment(special.AnswerText) // asr_score
		// 语调气场
		toneScore := report_service.FetchEmotion(variable.Config.UfsInfo.UfsUrl + variable.Config.UfsInfo.BucketPrefix + special.AnswerAudio)
		// 自信度(语气词评分)
		moodScore := report_service.FetchMood(special.AnswerText)
		// 语言流畅度
		languageFluencyScore := asrScore*0.5 + moodScore*0.5
		// 语言表达能力 = (语言流畅度+语调) / 2
		languageScore := (toneScore + languageFluencyScore) / 2.0

		// 主题评分
		themeScore = report_service.FetchFocusTopicScore(special.QuestionText, ans_text)

		// 题目评测得分
		topicScore = languageScore*0.2 + themeScore*0.3 + pointScore*0.5
		if special.CareerID == tables.QCivilServant {
			topicScore = themeScore*0.35 + special.MainPointScore*0.65
		}
		updates["asr_score"] = asrScore
		updates["tone"] = toneScore
		updates["mood"] = moodScore
		updates["language_fluency_score"] = languageFluencyScore
		updates["language_score"] = languageScore
		updates["theme_score"] = themeScore
		updates["topic_score"] = topicScore
		// 将对应的分数更新进入redis
		if int(topicScore) == 0 && (themeScore > 10 || moodScore > 10 || special.MainPointScore > 10) {
			fmt.Println("说明评分不准确，不予评分")
		} else {
			log.Logger.InfoF(ctx, fmt.Sprintf("total_score得分%d", int(topicScore)))
			sc := variable.DB.Redis.HSet(fmt.Sprintf(common.RedisSpecialInfoKey, special.ID), common.RedisHmapScore, int(topicScore))
			_, err := sc.Result()
			if err != nil {
				return err
			}
		}
		// 更新对应的评分项
		d := variable.DB.MySQL.Model(&tables.SpecialRecord{}).Where("id = ?", special.ID).Updates(updates).Limit(1)
		if d.Error != nil {
			return d.Error
		}
		// 更新redis & 结果得分 & 状态
		return s.updateSpecialScoreRedis(tables.SucStatus, int(topicScore), int(special.ID))
	}

}

// 专项练习信息
func (s *SpecialService) SpecialDetailScore(ctx *gin.Context, sid int64) (model.SpecialInfoRedisResp, error) {
	var out = model.SpecialInfoRedisResp{TotalScore: -1, Audio: "", TransStatus: 0}

	// 将对应的分数更新进入redis
	sc := variable.DB.Redis.HGetAll(fmt.Sprintf(common.RedisSpecialInfoKey, sid))
	m, _ := sc.Result()
	if _, ok := m[common.RedisHmapScore]; ok {
		totalScore, _ := strconv.Atoi(m[common.RedisHmapScore])
		out.TotalScore = totalScore
	}
	if _, ok := m[common.RedisHmapAudio]; ok {
		out.Audio = m[common.RedisHmapAudio]
	}
	if _, ok := m[common.RedisHmapTrans]; ok {
		transStatus, _ := strconv.Atoi(m[common.RedisHmapTrans])
		out.TransStatus = uint(transStatus)
	}
	if _, ok := m[common.RedisHmapAnswer]; ok {
		out.AnswerText = m[common.RedisHmapAnswer]
	}
	return out, nil
}

// 更新面试状态
func (s *SpecialService) UpdateSpecial(ctx *gin.Context, id uint, updateMap map[string]interface{}) error {
	var whereMap map[string]interface{}
	whereMap = make(map[string]interface{}, 0)
	whereMap["id"] = id
	_, err := new(tables.SpecialRecord).UpdateSpecial(whereMap, "", updateMap, 1)
	if err != nil {
		log.Logger.ErrorF(ctx, fmt.Sprintf("更新异常：%d", id))
		return err
	}
	return nil
}

// 判断5分钟内评分是否成功
func (s *SpecialService) JudgeSpecialReport(ctx *gin.Context) {
	for {
		sc := variable.DB.Redis.LPop(common.RedisSpecialQueue)
		s, _ := sc.Result()
		if len(s) == 0 {
			time.Sleep(3 * time.Second)
			continue
		}
		time.Sleep(1 * time.Second)
		id, _ := strconv.Atoi(s)
		whereStr := fmt.Sprintf("id = %d", id)

		var whereMap map[string]interface{}
		sr, _, _ := new(tables.SpecialRecord).GetSpecialListByWhere(whereMap, whereStr, "", "", -1, -1)
		if len(sr) != 0 {
			if sr[0].Status == tables.SucStatus {
				continue
			}
			if sr[0].FinishAt.IsZero() {
				continue
			}
			if !sr[0].FinishAt.IsZero() && sr[0].TotalScore == -1 && sr[0].Status == tables.ProStatus {
				err := new(SpecialService).UpdateScore(ctx, int(sr[0].ID))
				if err != nil {
					log.Logger.InfoMsgF(ctx, fmt.Sprintf("special try mark score error,id: [%d]", int(sr[0].ID)))
				}
				continue
			}
			log.Logger.InfoMsgF(ctx, fmt.Sprintf("special try mark score error,id: [%d]", int(sr[0].ID)))
			variable.DB.Redis.LPush(common.RedisSpecialQueue, sr[0].ID)
		}
	}
}

// 生成报告
func (s *SpecialService) DealSession(ctx *gin.Context) {
	for {
		// 取redis
		sc := variable.DB.Redis.LPop(common.RedisSessionIdsQueue)
		s, _ := sc.Result()
		if len(s) == 0 {
			time.Sleep(60 * time.Second)
			continue
		}
		id, _ := strconv.Atoi(s)
		url := fmt.Sprintf("https://mind.aminer.cn/prod/api/peilian/admin/session/report?session_id=%d&mark=false", id)
		fmt.Println(url)
		resp, err := http.Get(url)
		if err != nil {
			sdk.SendMsg(fmt.Sprintf("id:%d is error, %s", id, err.Error()))
			continue
		}
		if resp == nil || resp.Body == nil {
			sdk.SendMsg(fmt.Sprintf("id:%d is error, resp is error", id))
			continue
		}
		body, _ := io.ReadAll(resp.Body)
		fmt.Println("接口返回数据：" + string(body))
		defer resp.Body.Close()
		fmt.Println(fmt.Printf("url: %s, id: %d", url, id))
		time.Sleep(60 * time.Second)
	}
}

// 公务员数据特殊处理
func setSpecialGongwuyuan() {
	// 1. 查询career排序
	var tcs []tables.Career
	if d := variable.DB.MySQL.Model(&tables.Career{}).Where("id = 2").Find(&tcs); d.Error != nil {
		return
	}

	for i := 0; i < len(tcs); i++ {
		careerId := tcs[i].ID
		specialBase := tcs[i].SpecialBase
		SpecialAdvance := tcs[i].SpecialAdvance

		// 处理基础数据
		var ms []model.CareerCriteriaInfo
		json.Unmarshal([]byte(specialBase), &ms)
		var criterias []string
		variable.DB.MySQL.Model(&tables.Question{}).Distinct("criteria").Where("career_id = ?", careerId).Where("level = ?", "基础").Find(&criterias)
		if len(criterias) != 0 {
			for k, v := range ms {
				v.CareerId = careerId
				if !tools.Contains(criterias, v.Criteria) {
					v.IsEnable = false
				} else {
					if len(v.Num) != 0 {
						// 查询面试次数
						var count int64 = 0
						num, _ := strconv.Atoi(v.Num)
						variable.DB.MySQL.Model(&tables.SpecialRecord{}).Where("status = 1 and career_id = ? and criteria = ?", careerId, v.Criteria).Count(&count)
						v.Num = strconv.Itoa(num + int(count))
					}
				}

				ms[k] = v
			}
			// 存储redis 失败了也没关系
			b, _ := json.Marshal(ms)
			variable.DB.Redis.Set(fmt.Sprintf(common.RedisSpecialCriteriaKey, careerId, 1), string(b), -1)
		}

		// 处理进阶数据
		ms = []model.CareerCriteriaInfo{}
		json.Unmarshal([]byte(SpecialAdvance), &ms)
		criterias = []string{}
		variable.DB.MySQL.Model(&tables.Question{}).Distinct("criteria").Where("career_id = ?", careerId).Where("level = ?", "进阶").Find(&criterias)
		if len(criterias) != 0 {
			fmt.Println(careerId)
			fmt.Println(criterias)
			for k, v := range ms {
				v.CareerId = careerId
				if !tools.Contains(criterias, v.Criteria) {
					v.IsEnable = false
				} else {
					if len(v.Num) != 0 {
						// 查询面试次数
						var count int64 = 0
						num, _ := strconv.Atoi(v.Num)
						variable.DB.MySQL.Model(&tables.SpecialRecord{}).Where("status = 1 and career_id = ? and criteria = ?", careerId, v.Criteria).Count(&count)
						v.Num = strconv.Itoa(num + int(count))
					}
				}
				ms[k] = v
			}
			// 存储redis 失败了也没关系
			b, _ := json.Marshal(ms)
			variable.DB.Redis.Set(fmt.Sprintf(common.RedisSpecialCriteriaKey, careerId, 2), string(b), -1)
		}
	}
}

func (s *SpecialService) SetSpecialCareerList() {
	// 1. 查询career排序
	var tcs []tables.Career
	if d := variable.DB.MySQL.Model(&tables.Career{}).Where("special_base != ? ", "").Find(&tcs); d.Error != nil { // 只构建公务员的题库, 保留原样不变
		return
	}
	var careers = []int{1, 14, 15} // 公共能力+经验开放类 统一放入 通用岗位
	for i := 0; i < len(tcs); i++ {
		careerId := tcs[i].ID
		specialBase := tcs[i].SpecialBase
		SpecialAdvance := tcs[i].SpecialAdvance

		// 处理基础数据
		var ms []model.CareerCriteriaInfo
		json.Unmarshal([]byte(specialBase), &ms)
		var criterias []string
		if careerId != 1 {
			careers = []int{int(careerId)}
		}
		variable.DB.MySQL.Model(&tables.SpecialQuestion{}).Distinct("front_show_tag").Where("career_id in (?)", careers).Where("level = ?", "基础").Find(&criterias)
		if len(criterias) != 0 {
			for k, v := range ms {
				v.CareerId = careerId
				if !tools.Contains(criterias, v.Criteria) {
					v.IsEnable = false
				} else {
					if len(v.Num) != 0 {
						// 查询面试次数
						var count int64 = 0
						num, _ := strconv.Atoi(v.Num)
						variable.DB.MySQL.Model(&tables.SpecialRecord{}).Where("status = 1 and career_id = ? and criteria = ?", careerId, v.Criteria).Count(&count)
						v.Num = strconv.Itoa(num + int(count))
					}
				}

				ms[k] = v
			}
			// 存储redis 失败了也没关系
			b, _ := json.Marshal(ms)
			variable.DB.Redis.Set(fmt.Sprintf(common.RedisSpecialCriteriaKey, careerId, 1), string(b), -1) // 此处注意是  通用岗位的id
			fmt.Println(string(b))
		}

		// 处理进阶数据
		ms = []model.CareerCriteriaInfo{}
		json.Unmarshal([]byte(SpecialAdvance), &ms)
		criterias = []string{}
		variable.DB.MySQL.Model(&tables.SpecialQuestion{}).Distinct("front_show_tag").Where("career_id in (?)", careers).Where("level = ?", "进阶").Find(&criterias)
		if len(criterias) != 0 {
			for k, v := range ms {
				v.CareerId = careerId
				if !tools.Contains(criterias, v.Criteria) {
					v.IsEnable = false
				} else {
					if len(v.Num) != 0 {
						// 查询面试次数
						var count int64 = 0
						num, _ := strconv.Atoi(v.Num)
						variable.DB.MySQL.Model(&tables.SpecialRecord{}).Where("status = 1 and career_id = ? and criteria = ?", careerId, v.Criteria).Count(&count)
						v.Num = strconv.Itoa(num + int(count))
					}
				}
				ms[k] = v
			}
			// 存储redis 失败了也没关系
			b, _ := json.Marshal(ms)
			fmt.Println(string(b))
			variable.DB.Redis.Set(fmt.Sprintf(common.RedisSpecialCriteriaKey, careerId, 2), string(b), -1) // 此处注意是  通用岗位的id
		}
	}
	// 公务员特殊处理
	setSpecialGongwuyuan()
}
